package com.imis.base.config;

import com.github.xiaoymin.knife4j.spring.extension.OpenApiExtensionResolver;
import com.google.common.collect.Lists;
import com.imis.base.constant.HttpHeadersConstants;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;

import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * SwaggerConfiguration<br>
 * knife4j 配置类
 * </p>
 *
 * @author XinLau
 * @since 2020-03-12
 */
@Configuration
@EnableSwagger2WebMvc
public class SwaggerConfiguration implements WebMvcConfigurer {


    @Override
    public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {
        resourceHandlerRegistry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        resourceHandlerRegistry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        resourceHandlerRegistry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    private final OpenApiExtensionResolver openApiExtensionResolver;

    @Autowired
    public SwaggerConfiguration(OpenApiExtensionResolver openApiExtensionResolver) {
        this.openApiExtensionResolver = openApiExtensionResolver;
    }

    @Bean
    public Docket createCommonRestApi() {
        return createRestApi("登陆相关模块", "com.imis.module.api.controller", "登录、注册、注销、改密、登陆后获取功能菜单（带Token）、常用接口、下拉接口");
    }

    @Bean
    public Docket createWebSocketApi() {
        return createRestApi("即时通讯模块", "com.imis.module.websocket.controller", "即时通讯");
    }

    @Bean
    public Docket createBackstageManagementApi() {
        return createRestApi("后台管理模块", "com.imis.module.system.controller", "系统日志、字典管理、用户管理、角色管理、功能菜单、组织机构");
    }

    @Bean
    public Docket createDatabaseTableApi() {
        return createRestApi("数据库表模块", "com.imis.module.online.table.controller", "数据库表");
    }

    @Bean
    public Docket createFormManagementApi() {
        return createRestApi("表单开发模块", "com.imis.module.online.form.controller", "表单开发");
    }

    /***
     * oauth2配置
     * 需要增加swagger授权回调地址
     * http://localhost:8888/webjars/springfox-swagger-ui/o2c.html
     * @return SecurityScheme
     */
    @Bean
    SecurityScheme securityScheme() {
        return apiKey();
    }

    /**
     * swagger的配置文件，这里可以配置swagger的一些基本的内容，比如扫描的包等等
     *
     * @param groupName       - 模块名称
     * @param basePackageName - 扫描包
     * @param description     - 模块
     * @return Docket
     */
    private Docket createRestApi(final String groupName, final String basePackageName, final String description) {
        return new Docket(DocumentationType.SWAGGER_2)
                .groupName(groupName)
                .apiInfo(apiInfo(description))
                .select()
                // 此包路径下的类，才生成接口文档
                .apis(RequestHandlerSelectors.basePackage(basePackageName))
                // 加了ApiOperation注解的类，才生成接口文档
                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
                .paths(PathSelectors.any())
                .build()
                .securitySchemes(Lists.newArrayList(securityScheme()))
                // 添加将应用于所有操作的默认参数
                .globalOperationParameters(getGlobalOperationParameters())
                // 添加忽略类型
                // .ignoredParameterTypes(MultipartHttpServletRequest.class)
                // 通过Knife4j提供的工具对象OpenApiExtensionResolver将扩展属性进行赋值，实现自定义Swagger Models名称
                .extensions(openApiExtensionResolver.buildExtensions(groupName))
                ;
    }

    /**
     * JWT token
     *
     * @return List<Parameter>
     */
    private List<Parameter> getGlobalOperationParameters() {
        // 参数数组
        List<Parameter> pars = new ArrayList<>();
        String name = "";
        String defaultValue = "";
        String description = "";
        String type = "";
        String paramType = "";
        Boolean required = Boolean.FALSE;
        // pars.add(getParameter(name, defaultValue, description, type, paramType, required));
        return pars;
    }

    /**
     * 参数生成器
     *
     * @param name         - 更新参数名称
     * @param defaultValue - 更新参数的默认值
     * @param description  - 更新参数说明
     * @param type         - 表示推断模型参考的便捷方法合并或弄清楚哪些内容可以汇总
     * @param paramType    - 更新参数类型
     * @param required     - 更新参数是否为必需或可选
     * @return Parameter
     */
    private Parameter getParameter(String name, String defaultValue, String description, String type, String paramType, Boolean required) {
        // 参数生成器
        return new ParameterBuilder()
                // 更新参数名称
                .name(name)
                // 更新参数的默认值
                .defaultValue(defaultValue)
                // 更新参数说明
                .description(description)
                // 表示推断模型参考的便捷方法合并或弄清楚哪些内容可以汇总
                .modelRef(new ModelRef(type))
                // 更新参数类型
                .parameterType(paramType)
                // 更新参数是否为必需或可选
                .required(required)
                // 构建
                .build();
    }

    /**
     * 获取ApiKey
     *
     * @return ApiKey
     */
    private ApiKey apiKey() {
        return new ApiKey(HttpHeadersConstants.X_ACCESS_TOKEN, HttpHeadersConstants.X_ACCESS_TOKEN, "header");
    }

    /**
     * api文档的详细信息函数,注意这里的注解引用的是哪个
     *
     * @param description - 描述
     * @return
     */
    private ApiInfo apiInfo(final String description) {
        return new ApiInfoBuilder()
                // 大标题
                .title("后台服务API接口文档")
                // 版本号
                .version("1.0")
                // 条款服务URL
                // .termsOfServiceUrl("NO terms of service")
                // 描述
                .description(description)
                // 联系人信息
                .contact(new Contact("XinLau", "https://github.com/XinLau1996", "xiaotaiye1996@gmail.com"))
                // 许可证
                .license("The Apache License, Version 2.0")
                // 许可证URL
                .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
                .build();
    }

}
